package org.dxy.trigger.http.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.api.dto.request.product.*;
import org.dxy.api.response.R;
import org.dxy.domain.port.CommandHandler;
import org.dxy.domain.command.product.*;
import org.dxy.domain.model.valobj.Bom;
import org.dxy.domain.model.valobj.BomItem;
import org.dxy.infrastructure.persistent.db.mybatispuls.po.query.BomItemViewPo;
import org.dxy.infrastructure.persistent.db.mybatispuls.po.query.BomViewPo;
import org.dxy.infrastructure.persistent.db.mybatispuls.po.query.ProductViewPo;
import org.dxy.infrastructure.persistent.db.mybatispuls.service.BomItemViewService;
import org.dxy.infrastructure.persistent.db.mybatispuls.service.BomViewService;
import org.dxy.infrastructure.persistent.db.mybatispuls.service.ProductViewService;

import org.dxy.trigger.http.service.ProductApplicationService;
import org.dxy.types.common.CommandResult;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 产品应用服务实现类
 * @author dxy
 * @createTime 2025/8/17
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductApplicationServiceImpl implements ProductApplicationService {
    
    private final CommandHandler<CreateProductCommand, Long> createHandler;
    private final CommandHandler<UpdateProductCommand, Void> updateHandler;
    private final CommandHandler<EnableProductCommand, Void> enableHandler;
    private final CommandHandler<DisableProductCommand, Void> disableHandler;
    private final CommandHandler<DeleteProductCommand, Void> deleteHandler;
    private final CommandHandler<ChangeProductVersionCommand, Void> changeVersionHandler;
    private final CommandHandler<AssignProductRouteCommand, Void> assignRouteHandler;
    private final CommandHandler<UpdateProductBOMCommand, Void> updateBOMHandler;
    private final CommandHandler<UnassignProductRouteCommand, Void> unassignRouteHandler;
    private final CommandHandler<ApproveProductCommand, Void> approveHandler;
    private final CommandHandler<RejectProductCommand, Void> rejectHandler;
    private final ProductViewService productViewService;
    private final BomViewService bomViewService;
    private final BomItemViewService bomItemViewService;
    @Transactional
    @Override
    public R<Long> create(CreateProductRequest request) {
        try {
            // 1. 构建核心业务命令（只包含聚合根必需的字段）
            CreateProductCommand command = new CreateProductCommand(
                    request.getProductCode(),
                    request.getProductName(),
                    request.getType(),
                    request.getVersion(),
                    request.getUnit(),
                    request.getBom()
            );
            
            // 2. 执行命令（写操作）- 只处理核心业务逻辑
            CommandResult<Long> result = createHandler.handle(command);
            
            if (result.success()) {
                // 3. CQRS: 命令执行成功后，直接更新读模型
                // 创建产品读模型（包含所有字段：核心业务字段 + 展示字段）
                ProductViewPo productView = ProductViewPo.builder()
                        .id(result.data())
                        .productCode(request.getProductCode())
                        .productName(request.getProductName())
                        .model(request.getModel())           // 展示字段
                        .category(request.getCategory())     // 展示字段
                        .type(request.getType())
                        .specification(request.getSpecification()) // 展示字段
                        .version(request.getVersion())
                        .unit(request.getUnit())
                        .status("created")
                        .build();
                
                productViewService.save(productView);
                
                // 如果有BOM信息，创建BOM读模型
                if (request.getBom() != null) {
                    createBomReadModel(result.data(), request.getBom());
                }
                 
                log.info("产品创建命令执行成功, productId={}", result.data());
                return R.ok(result.data(), result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("创建产品失败", e);
            return R.fail("创建产品失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> update(Long productId, UpdateProductRequest request) {
        try {
            // 1. 构建核心业务命令（只包含聚合根必需的字段）
            UpdateProductCommand command = new UpdateProductCommand(
                    productId,
                    request.getProductName(),
                    request.getType(),
                    request.getVersion(),
                    request.getUnit(),
                    request.getBom()
            );
            
            // 2. 执行命令（写操作）- 只处理核心业务逻辑
            CommandResult<Void> result = updateHandler.handle(command);
            
            if (result.success()) {
                // 3. CQRS: 命令执行成功后，直接更新读模型
                // 更新产品读模型（包含所有字段：核心业务字段 + 展示字段）
                ProductViewPo existingProduct = productViewService.getById(productId);
                if (existingProduct != null) {
                    existingProduct.setProductName(request.getProductName());
                    existingProduct.setModel(request.getModel());           // 展示字段
                    existingProduct.setCategory(request.getCategory());     // 展示字段
                    existingProduct.setType(request.getType());
                    existingProduct.setSpecification(request.getSpecification()); // 展示字段
                    existingProduct.setVersion(request.getVersion());
                    existingProduct.setUnit(request.getUnit());
                    
                    productViewService.updateById(existingProduct);
                }
                
                // 更新BOM读模型
                updateBomReadModel(productId, request.getBom());
                
                log.info("产品更新命令执行成功, productId={}", productId);
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("更新产品失败, productId={}", productId, e);
            return R.fail("更新产品失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> enable(Long productId) {
        try {
            EnableProductCommand command = new EnableProductCommand(productId);
            CommandResult<Void> result = enableHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("启用产品失败, productId={}", productId, e);
            return R.fail("启用产品失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> disable(Long productId) {
        try {
            DisableProductCommand command = new DisableProductCommand(productId);
            CommandResult<Void> result = disableHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("禁用产品失败, productId={}", productId, e);
            return R.fail("禁用产品失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> delete(Long productId) {
        try {
            DeleteProductCommand command = new DeleteProductCommand(productId);
            CommandResult<Void> result = deleteHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("删除产品失败, productId={}", productId, e);
            return R.fail("删除产品失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> changeVersion(Long productId, ChangeProductVersionRequest request) {
        try {
            ChangeProductVersionCommand command = new ChangeProductVersionCommand(
                    productId, request.getNewVersion());
            CommandResult<Void> result = changeVersionHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("变更产品版本失败, productId={}", productId, e);
            return R.fail("变更产品版本失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> updateBOM(Long productId) {
        try {
            UpdateProductBOMCommand command = new UpdateProductBOMCommand(productId);
            CommandResult<Void> result = updateBOMHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("更新产品BOM失败, productId={}", productId, e);
            return R.fail("更新产品BOM失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> assignRoute(Long productId, AssignProductRouteRequest request) {
        try {
            AssignProductRouteCommand command = new AssignProductRouteCommand(
                    productId, request.getRouteId());
            CommandResult<Void> result = assignRouteHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("分配产品工艺路线失败, productId={}", productId, e);
            return R.fail("分配产品工艺路线失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> unassignRoute(Long productId, Long routeId) {
        try {
            UnassignProductRouteCommand command = new UnassignProductRouteCommand(productId, routeId);
            CommandResult<Void> result = unassignRouteHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("解绑产品工艺路线失败, productId={}, routeId={}", productId, routeId, e);
            return R.fail("解绑产品工艺路线失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> approve(Long productId) {
        try {
            ApproveProductCommand command = new ApproveProductCommand(productId);
            CommandResult<Void> result = approveHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("审核通过产品失败, productId={}", productId, e);
            return R.fail("审核通过产品失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> reject(Long productId, RejectProductRequest request) {
        try {
            RejectProductCommand command = new RejectProductCommand(productId, request.getReason());
            CommandResult<Void> result = rejectHandler.handle(command);
            
            if (result.success()) {
                return R.ok(result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("审核驳回产品失败, productId={}", productId, e);
            return R.fail("审核驳回产品失败: " + e.getMessage());
        }
    }

    @Override
    public R<Page<ProductViewPo>> list(Page<ProductViewPo> page, ProductViewPo query) {
        try {
            LambdaQueryWrapper<ProductViewPo> queryWrapper = new LambdaQueryWrapper<>();
            
            if (query != null) {
                if (query.getProductCode() != null && !query.getProductCode().isEmpty()) {
                    queryWrapper.like(ProductViewPo::getProductCode, query.getProductCode());
                }
                if (query.getProductName() != null && !query.getProductName().isEmpty()) {
                    queryWrapper.like(ProductViewPo::getProductName, query.getProductName());
                }
                if (query.getStatus() != null && !query.getStatus().isEmpty()) {
                    queryWrapper.eq(ProductViewPo::getStatus, query.getStatus());
                }
            }
            
            Page<ProductViewPo> result = productViewService.page(page, queryWrapper);
            return R.ok(result, "查询成功");
        } catch (Exception e) {
            log.error("查询产品列表失败", e);
            return R.fail("查询产品列表失败: " + e.getMessage());
        }
    }

    @Override
    public R<ProductViewPo> getById(Long productId) {
        try {
            ProductViewPo product = productViewService.getById(productId);
            if (product != null) {
                // 如果需要返回包含BOM信息的详细响应，可以转换为ProductDetailResponse
                // 这里为了保持接口一致性，仍然返回ProductViewEntity
                // 但在实际使用中，前端需要解析bomJson字段
                return R.ok(product, "查询成功");
            } else {
                return R.fail("产品不存在");
            }
        } catch (Exception e) {
            log.error("查询产品详情失败, productId={}", productId, e);
            return R.fail("查询产品详情失败: " + e.getMessage());
        }
    }

    @Override
    public R<Page<ProductViewPo>> getByStatus(Page<ProductViewPo> page, String status) {
        try {
            LambdaQueryWrapper<ProductViewPo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ProductViewPo::getStatus, status);
            
            Page<ProductViewPo> result = productViewService.page(page, queryWrapper);
            return R.ok(result, "查询成功");
        } catch (Exception e) {
            log.error("根据状态查询产品列表失败, status={}", status, e);
            return R.fail("根据状态查询产品列表失败: " + e.getMessage());
        }
    }

    @Override
    public R<Object> getBOMByProductId(Long productId) {
        try {
            // 1. 查询BOM主信息
            BomViewPo bomView = bomViewService.getByProductId(productId);
            if (bomView == null) {
                return R.ok(null, "该产品暂无BOM信息");
            }
            
            // 2. 查询BOM物料项
            List<BomItemViewPo> bomItems = bomItemViewService.listByBomId(bomView.getId());
            
            // 3. 构建BOM响应对象
            Bom bomResponse = buildBomResponse(bomView, bomItems);
            
            return R.ok(bomResponse, "查询成功");
        } catch (Exception e) {
            log.error("查询产品BOM信息失败, productId={}", productId, e);
            return R.fail("查询产品BOM信息失败: " + e.getMessage());
        }
    }
    
    /**
     * 构建BOM响应对象 - 返回Domain值对象
     */
    private Bom buildBomResponse(BomViewPo bomView, List<BomItemViewPo> bomItems) {
        // 构建物料项列表（支持多层级结构）
        List<BomItem> items = buildBomItemsTree(bomItems, null);
        
        return new Bom(
            bomView.getBomVersion(),
            bomView.getBomType(),
            bomView.getStatus(),
            bomView.getSource(),
            bomView.getEffectiveDate(),
            bomView.getExpiredDate(),
            items
        );
    }
    
    /**
     * 构建BOM物料项树形结构 - 返回Domain值对象
     */
    private List<BomItem> buildBomItemsTree(List<BomItemViewPo> allItems, Long parentId) {
        return allItems.stream()
                .filter(item -> Objects.equals(item.getParentId(), parentId))
                .map(item -> {
                    // 递归构建子级物料项
                    List<BomItem> children = buildBomItemsTree(allItems, item.getId());
                    
                    return new BomItem(
                        item.getMaterialCode(),
                        item.getMaterialName(),
                        item.getQuantity(),
                        item.getUnit(),
                        item.getRemark(),
                        children
                    );
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 创建BOM读模型
     */
    private void createBomReadModel(Long productId, Bom bom) {
        if (bom == null) return;
        
        // 1. 创建BOM主表记录
        BomViewPo bomView = BomViewPo.builder()
                .productId(productId)
                .bomVersion(bom.bomVersion())
                .bomType(bom.bomType())
                .status(bom.status())
                .source(bom.source())
                .effectiveDate(bom.effectiveDate())
                .expiredDate(bom.expiredDate())
                .build();
        
        bomViewService.save(bomView);
        
        // 2. 创建BOM物料项记录
        if (bom.items() != null && !bom.items().isEmpty()) {
            createBomItemsReadModel(bomView.getId(), bom.items(), null, 1);
        }
    }
    
    /**
     * 创建BOM物料项读模型（支持多层级结构）
     */
    private void createBomItemsReadModel(Long bomId, List<BomItem> items, Long parentId, int level) {
        for (int i = 0; i < items.size(); i++) {
            BomItem item = items.get(i);
            
            BomItemViewPo bomItemView = BomItemViewPo.builder()
                    .bomId(bomId)
                    .parentId(parentId)
                    .materialCode(item.materialCode())
                    .materialName(item.materialName())
                    .quantity(item.quantity())
                    .unit(item.unit())
                    .remark(item.remark())
                    .level(level)
                    .sortOrder(i + 1)
                    .build();
            
            bomItemViewService.save(bomItemView);
            
            // 递归处理子级物料项
            if (item.children() != null && !item.children().isEmpty()) {
                createBomItemsReadModel(bomId, item.children(), bomItemView.getId(), level + 1);
            }
        }
    }
    
    /**
     * 更新BOM读模型
     */
    private void updateBomReadModel(Long productId, Bom bom) {
        // 1. 删除现有的BOM数据
        BomViewPo existingBom = bomViewService.getByProductId(productId);
        if (existingBom != null) {
            // 删除BOM物料项
            bomItemViewService.deleteByBomId(existingBom.getId());
            // 删除BOM主记录
            bomViewService.removeById(existingBom.getId());
        }
        
        // 2. 如果有新的BOM信息，创建新的BOM读模型
        if (bom != null) {
            createBomReadModel(productId, bom);
        }
    }
}